import importlib
import json
import logging.config as lc
import re
import tensorflow as tf
import os
import subprocess
import logging
from logging.handlers import RotatingFileHandler
import sys
import torch

def dynamic_import(importPath):
    moduleName,objname=importPath.split(':')
    m=importlib.import_module(moduleName)
    return getattr(m,objname)

def load_logging_config():
    lc.fileConfig('common/logger.conf')

def load_from_json(json_file):
    with open(json_file,encoding='utf8') as f:
        return json.load(f)
    
def dump_json(json_,json_file):
    with open(json_file,'w',encoding='utf8') as f:
        json.dump(json_,f,ensure_ascii=False,indent=4)

def getStrOriValue(st):
    if st.startswith('('):
        return parseParams(st[1:-1])[0]
    elif st.startswith('['):
        return list(parseParams(st[1:-1])[0])
    elif st.startswith('{'):
        return json.loads(st)  # 测试人员写字典字符串时，如果想表达True的概念，要写成true,因为json中true的写法是小写t,据此json识别出true并转成python中True,False同理
    elif st.startswith('"') or st.startswith('\''):
        return str(st[1:-1])
    elif st=='True':
        return True
    elif st=='False':
        return False
    elif st=='None':
        return None
    elif re.match(r'^[\+\-]?\d+$',st):
        return int(st)
    elif re.match(r'^[\+\-]?\d+(\.\d+)?e[\+\-]?\d+([\+\-]{1}\d+)*$',st) or re.match(r'^[\+\-]?\d+\.\d+$',st):
        return float(st)
    else:
        return str(st)

def str2oriValue(st,t,d):
    searchResult=re.search(r'^(\w+)=(.+)',st)
    if searchResult is None:
        t.append(getStrOriValue(st))
    else:
        d[searchResult.group(1)]=getStrOriValue(searchResult.group(2))

def parseParams(parameters):
    t=[]
    d={}
    orii=i=0
    oneParamFlag=0
    doubleQuoteFlag=False
    uniqueQuoteFlag=False
    parameters=''.join(parameters.split())
    while i<len(parameters):
        if not oneParamFlag and not doubleQuoteFlag and not uniqueQuoteFlag and parameters[i]==',':
            str2oriValue(parameters[orii:i],t,d)
            orii=i+1
        if parameters[i] in ('(','[','{'):
            oneParamFlag+=1
        elif parameters[i] in (')',']','}'):
            oneParamFlag-=1
        elif parameters[i]=='"':
            doubleQuoteFlag=not doubleQuoteFlag
        elif parameters[i]=='\'':
            uniqueQuoteFlag=not uniqueQuoteFlag
        i+=1
    if orii<len(parameters):
        str2oriValue(parameters[orii:],t,d)
    return tuple(t),d

def return_ins(modulename,classname,parameters,attribute):
    obj=dynamic_import(f'{modulename}:{classname}')
    t,d=parseParams(parameters)
    
    ins=obj(*t,**d)
    if attribute=='':
        return ins
    else:
        func_params=attribute.split('(',1)
        ins=getattr(ins,func_params[0])
        if len(func_params)>1:
            t,d=parseParams(func_params[1][:-1])
            return ins(*t,**d)
        else:
            return ins
        
def load_weights_keras(model,weights_file,weights_type):
    # if weights_type=='weights':
    if weights_type==0:
        model.load_weights(weights_file)
    # elif weights_type=='ckpt':
    elif weights_type==1:
        if os.path.isdir(weights_file):
            tf.train.Checkpoint(net=model).restore(tf.train.latest_checkpoint(weights_file))
        else:
            tf.train.Checkpoint(net=model).restore(weights_file)
    # model.save_weights('/home/tellw/saved_models/model.weights.h5')

def load_weights_pytorch(model,weights_file,weights_type):
    # if weights_type=='torch_state_dict':
    if weights_type==2:
        model.load_state_dict(torch.load(weights_file))

def load_model_from_framework_save_keras(file,file_ext):
    # if file_ext=='saved_model':
    if file_ext==0:
        return tf.keras.models.load_model(file)
    # elif file_ext=='json':
    elif file_ext==1:
        with open(file) as f:
            js=f.read()
        return tf.keras.models.model_from_json(js)
    # elif file_ext=='config':
    elif file_ext==2:
        with open(file) as f:
            cs=f.read()
        return tf.keras.Model.from_config(dict(cs))
    
def load_model_from_framework_save_pytorch(file,file_ext):
    # if file_ext=='torch_model':
    if file_ext==3:
        return torch.load(file)
    
def exec_shell(cmd, ignore_err=False):
    process = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
    output, err = process.communicate()
    retcode = process.poll()
    if retcode == 0 or ignore_err:
        return output, err
    else:
        return -1000, f'execute "{cmd}" failed'
    
def init_log(log_path='logger.log'):
    if not os.path.exists(os.path.dirname(log_path)):
        os.makedirs(os.path.dirname(log_path))
    logging.getLogger('').setLevel(logging.INFO)
    # console=logging.StreamHandler(sys.stdout)
    formatter=logging.Formatter('%(levelname)s %(asctime)s %(thread)d %(filename)s[line:%(lineno)d]: %(message)s')
    # console.setFormatter(formatter)
    # logging.getLogger('').addHandler(console)
    rotating_file=RotatingFileHandler(log_path,'a',100*1024*1024,5)
    rotating_file.setFormatter(formatter)
    logging.getLogger('').addHandler(rotating_file)

if __name__=='__main__':
    print(parseParams(''))